#ifndef __M_DATA_H__
#define __M_DATA_H__
#include<unordered_map>
#include<pthread.h>
#include"util.hpp"
#include"config.hpp"
namespace vic_cloud
{
    //数据信息结构体
typedef struct BackupInfo_t{
	bool _pack_flag;//是否压缩标志
	time_t _mtime;//最后修改时间
	time_t _atime;//最后访问时间
	size_t _fsize;//文件大小
	std::string _real_path;//文件实际存储路径名
	std::string _url_path;//请求的资源路径
	std::string _pack_path;//压缩报存储路径名
    //数据填充（获取各项属性信息，存储到BackupInfo结构体）
	bool NewBackupInfo(const std::string &realpath)
    {
        FileUtil f(realpath);
        if(f.Exists()==false)
        { 
            std::cout<<"new backupfile file not find\n";
            return false;
        }
        Config* config=Config::GetInstance();
        std::string packdir=config->GetPackDir();
        std::string packsuffix=config->GetPackFileSuffix();
        std::string downloadprefix=config->GetDownloadPrefix();
        
        this->_pack_flag=false;
        this->_fsize=f.FileSize();
        this->_mtime=f.LastModifyTime();
        this->_atime=f.LastAcccessTime();
        this->_real_path=realpath;
        // ./backdir/a.txt --> ./packdir/a.txt.lz
        this->_pack_path=packdir+f.FileName()+packsuffix;
        // ./backdir/a.txt --> /download/a.txt
        this->_url_path=downloadprefix+f.FileName();
        return true;
    }
}BackupInfo;


//数据管理类
class DataManager{
private:
	std::string  _backup_file;//持久化存储文件
	pthread_rwlock_t _rwlock;//读写锁，读共享，写互斥
	std::unordered_map<std::string, BackupInfo> _table;//内存中hash存储的文件信息管理表
public:
	DataManager()
    {
        _backup_file=Config::GetInstance()->GetBackupFile();
        //读写锁初始化
        pthread_rwlock_init(&_rwlock,NULL);
        InitLoad();
    }
    ~DataManager()
    {
        //销毁锁初始化
        pthread_rwlock_destroy(&_rwlock);
    }
    //初始化加载，每次系统重启都要加载以嵌的数据
	bool InitLoad()
    {
        //1.读取backup_file备份信息的存放文件中的数据
        FileUtil f(_backup_file);
        if(f.Exists()==false)
        {
            return true;
        }
        std::string body;
        if(f.GetContent(&body)==false)
        {
            std::cout<<"InitTable failed\n";
            return false;
        }
        //2.反序列化
        Json::Value root;
        JsonUtil::UnSerialize(body,&root);
        //3.将反序列化得到的Json::Value中的数据添加到table中
        for(int i=0;i<root.size();i++)
        {
            BackupInfo info;
            info._pack_flag=root[i]["pack_flag"].asBool();
            info._fsize=root[i]["fsize"].asInt64();
            info._atime=root[i]["atime"].asInt64();
            info._mtime=root[i]["mtime"].asInt64();
            info._pack_path=root[i]["pack_path"].asString();
            info._real_path=root[i]["real_path"].asString();
            info._url_path=root[i]["url_path"].asString();
            Insert(info);


        }
        return true;
    }
    //每次有信息改变则需要持久化存储一次
	bool Storage()
    {
        // //1.获取所有数据 
        // std::vector<BackupInfo> arr;
        // this->GetAll(&arr);
        // //2.填充到Json::Value中
        // Json::Value root;
        // for(int i=0;i<arr.size();i++)
        // {
        //     Json::Value val;
        //     val["pack_flag"]=arr[i]._pack_flag;
        //     val["fsize"]=(Json::Int64)arr[i]._fsize;
        //     val["atime"]=(Json::Int64)arr[i]._atime;
        //     val["real_path"]=arr[i]._real_path;
        //     val["pack_path"]=arr[i]._pack_path;
        //     val["url_path"]=arr[i]._url_path;
        //     root.append(val);

        // }
        // //3.对Json::Value序列化
        // std::string body;
        // JsonUtil::Serialize(root,&body);
        // //4.写文件
        // FileUtil f(_backup_file);
        // f.SetContent(body);
        // return true;
         // 1. 将table Json序列化
            Json::Value root;
            for (auto t : _table)
            {
                Json::Value val;
                val["pack_flag"] = t.second._pack_flag;
                // Json支持内置类型，因此size_t和time_t都需强转
                val["fsize"] = (Json::Int64)t.second._fsize;
                val["atime"] = (Json::Int64)t.second._atime;
                val["mtime"] = (Json::Int64)t.second._mtime;
                val["real_path"] = t.second._real_path;
                val["pack_path"] = t.second._pack_path;
                val["url_path"] = t.second._url_path;
 
                root.append(val);
            }
            std::string str;
            JsonUtil::Serialize(root, &str);
            // 2. 写入存储文件
            FileUtil fu(_backup_file);
            if (fu.SetContent(str) == false)
            {
                std::cout << "storage failed" << std::endl;
                return false;
            }
 
            return true;

    }
    //新增
    bool Insert(const BackupInfo &info)
    {
        pthread_rwlock_wrlock(&_rwlock);//读写锁加锁
        _table[info._url_path]=info;
        pthread_rwlock_unlock(&_rwlock);
        Storage();
        return true;
    }
    //修改
	bool Update(const BackupInfo &info)
    {
        pthread_rwlock_wrlock(&_rwlock);//读写锁加锁
        _table[info._url_path]=info;
        pthread_rwlock_unlock(&_rwlock);
        Storage();

        return true;

    }
    //根据请求url获取对应文件信息（用户根据url请求下载文件）
	bool GetOneByURL(const std::string &url, BackupInfo *info)
    {
        pthread_rwlock_wrlock(&_rwlock);//读写锁加锁
        auto it =_table.find(url);//url是key值直接find查找
        if(it==_table.end())
        {
            std::cout << "file unexist" << std::endl;
            pthread_rwlock_unlock(&_rwlock);

            return false;
        }
        *info=it->second;
        pthread_rwlock_unlock(&_rwlock);

        return true;

    }
    //根据真实路径获取文件信息，(服务器端测备份文件 热点文件判断）
	bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
    {
        pthread_rwlock_wrlock(&_rwlock);//读写锁加锁
        auto it =_table.begin();
        //真实路径需要遍历unordered_map 中second的real_path
        for(;it!=_table.end();it++)
        {
            if(it->second._real_path==realpath)
            {
                *info=it->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;

            }
        }
        pthread_rwlock_unlock(&_rwlock);
        return false;

    }
    //获取所有文件信息
	bool GetAll(std::vector<BackupInfo> *arry)
    {
        pthread_rwlock_wrlock(&_rwlock);//读写锁加锁
        //遍历
        auto it =_table.begin();
        for(;it!=_table.end();it++)
        {
            arry->push_back(it->second);
        }
        pthread_rwlock_unlock(&_rwlock);
        return true;

    }
};
}
#endif